package com.hmall.trade.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.api.client.CartClient;
import com.hmall.api.client.ItemClient;
import com.hmall.api.client.PayClient;
import com.hmall.api.domain.dto.ItemDTO;
import com.hmall.common.config.RabbitMqHelper;
import com.hmall.common.exception.BadRequestException;
import com.hmall.common.utils.UserContext;

import com.hmall.api.domain.dto.OrderDetailDTO;
import com.hmall.trade.domain.dto.OrderFormDTO;
import com.hmall.trade.domain.po.Order;
import com.hmall.trade.domain.po.OrderDetail;
import com.hmall.trade.mapper.OrderMapper;
import com.hmall.trade.service.IOrderDetailService;
import com.hmall.trade.service.IOrderService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.hmall.trade.constans.MqConstance.DELAY_EXCHANGE_NAME;
import static com.hmall.trade.constans.MqConstance.DELAY_ORDER_KEY;

@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    private final ItemClient itemClient;
    private final CartClient cartClient;
    private final PayClient payClient;
    private final IOrderDetailService detailService;
    private final RabbitTemplate rabbitTemplate;
    private final RabbitMqHelper rabbitMqHelper;

    @Override
    @GlobalTransactional//标记事务的起点开启全局事务
    public Long createOrder(OrderFormDTO orderFormDTO) {
        // 1.订单数据
        Order order = new Order();
        // 1.1.查询商品
        List<OrderDetailDTO> detailDTOS = orderFormDTO.getDetails();
        // 1.2.获取商品id和数量的Map
        Map<Long, Integer> itemNumMap = detailDTOS.stream()
                .collect(Collectors.toMap(OrderDetailDTO::getItemId, OrderDetailDTO::getNum));
        Set<Long> itemIds = itemNumMap.keySet();
        // 1.3.查询商品
        List<ItemDTO> items = itemClient.queryItemByids(itemIds);
        if (items == null || items.size() < itemIds.size()) {
            throw new BadRequestException("商品不存在");
        }
        // 1.4.基于商品价格、购买数量计算商品总价：totalFee
        int total = 0;
        for (ItemDTO item : items) {
            total += item.getPrice() * itemNumMap.get(item.getId());
        }
        order.setTotalFee(total);
        // 1.5.其它属性
        order.setPaymentType(orderFormDTO.getPaymentType());
        order.setUserId(UserContext.getUser());
        order.setStatus(1);
        // 1.6.将Order写入数据库order表中
        save(order);

        // 2.保存订单详情
        List<OrderDetail> details = buildDetails(order.getId(), items, itemNumMap);
        detailService.saveBatch(details);

        // 3.清理购物车商品
        //cartClient.removeByItemIds(itemIds);
        //MessagePostProcessor 作用是在发送消息前对消息进行处理传递用户id
        //rabbitTemplate.convertAndSend("trade.topic", "order.create", itemIds);
        /*rabbitTemplate.convertAndSend("trade.topic", "order.create", itemIds, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setHeader("userId", UserContext.getUser());
                return message;
            }
                });*/
        rabbitMqHelper.sendMessageWithConfirm("trade.topic", "order.create", itemIds, 3);

        // 4.扣减库存
        try {
            itemClient.deductStock(detailDTOS);
            //rabbitTemplate.convertAndSend("trade.topic", "order.create",detailDTOS);
        } catch (Exception e) {
            throw new RuntimeException("库存不足！");
        }

        //改造下单业务，发送延迟消息 自己发送自己接收
        /*rabbitTemplate.convertAndSend(DELAY_EXCHANGE_NAME, DELAY_ORDER_KEY, order.getId(),
                new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        //10秒后去查询
                        message.getMessageProperties().setDelay(10000);
                        return message;
                    }
                });*/
        rabbitMqHelper.sendDelayMessage(DELAY_EXCHANGE_NAME, DELAY_ORDER_KEY, order.getId(), 10000000);
        return order.getId();
    }

    // 标记order订单支付成功
    @Override
    public void markOrderPaySuccess(Long orderId) {
       /* //业务幂等判断 目的就是尽可能避免业务被重复执行
        Order orders = getById(orderId);
        if(orders == null || orders.getStatus() != 1 ){
            //直接确保肯定被消费一次
            return;
        }
        Order order = new Order();
        order.setId(orderId);
        order.setStatus(2);
        order.setPayTime(LocalDateTime.now());
        updateById(order);*/

        //根据原子性原则这里会出现线程安全问题，所以需要使用乐观锁在修改之前再判断支付状态是否修改
        lambdaUpdate()
                .set(Order::getStatus, 2)
                .set(Order::getPayTime, LocalDateTime.now())
                .eq(Order::getId, orderId)
                .eq(Order::getStatus, 1)
                .update();
    }

    //构建订单详情
    private List<OrderDetail> buildDetails(Long orderId, List<ItemDTO> items, Map<Long, Integer> numMap) {
        List<OrderDetail> details = new ArrayList<>(items.size());
        for (ItemDTO item : items) {
            OrderDetail detail = new OrderDetail();
            detail.setName(item.getName());
            detail.setSpec(item.getSpec());
            detail.setPrice(item.getPrice());
            detail.setNum(numMap.get(item.getId()));
            detail.setItemId(item.getId());
            detail.setImage(item.getImage());
            detail.setOrderId(orderId);
            details.add(detail);
        }
        return details;
    }
    //取消订单
    @Override
    public void cancelOrder(Long orderId) {
        //1.取消订单更改支付状态
        lambdaUpdate()
                .set(Order::getStatus, 5)
                .eq(Order::getId, orderId)
                .update();
        //2.修改支付状态为已取消
        payClient.cancelPayOrder(orderId, 2);
        //恢复库存
        List<OrderDetail> details = detailService.lambdaQuery()
                .eq(OrderDetail::getOrderId, orderId)
                .list();
        //map方法是将一个对象转换成另一个对象
        List<OrderDetailDTO> detailDTOS = details.stream()
                        .map(detail -> {
                            OrderDetailDTO detailDTO = new OrderDetailDTO();
                            detailDTO.setItemId(detail.getItemId());
                            detailDTO.setNum(detail.getNum());
                            return detailDTO;
                        }).collect(Collectors.toList());

        //List<OrderDetailDTO> orderDetailDTOS = BeanUtil.copyToList(details, OrderDetailDTO.class);
        itemClient.restoreStock(detailDTOS);

    }
}
